{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 为MNIST数据集构建一个分类器，并在测试集上达成超过90%的精度 10分\n",
    "提示：KNeighborsClassifier对这个任务非常有效，你只需要找到合适的超参数即可，可对weights和n_neighbors这两个超参数进行网格搜索"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 获取数据集"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "c:\\users\\yxx\\appdata\\local\\programs\\python\\python38\\lib\\site-packages\\sklearn\\feature_extraction\\text.py:17: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated since Python 3.3, and in 3.9 it will stop working\n",
      "  from collections import Mapping, defaultdict\n"
     ]
    }
   ],
   "source": [
    "from sklearn.datasets import fetch_mldata\n",
    "\n",
    "#导入数据\n",
    "mnist=fetch_mldata(\"mnist-original\",data_home=\"./\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "X=mnist[\"data\"]\n",
    "y=mnist[\"target\"]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 拆分数据集"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "X_train,X_test,y_train,y_test=X[:60000,:],X[60000:,:],y[:60000],y[60000:]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import sklearn\n",
    "import matplotlib.pyplot as plt\n",
    "import pandas as pd"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 打乱数据顺序"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "shuffle_index=np.random.permutation(60000)\n",
    "X_train,y_train=X_train[shuffle_index],y[shuffle_index]\n",
    "shuffle_index=np.random.permutation(10000)\n",
    "X_test,y_test=X_test[shuffle_index],y_test[shuffle_index]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 随意确定一个值\n",
    "some_digit=X_train[39000]\n",
    "some_digit_img=some_digit.reshape(28,28)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "import matplotlib"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "%matplotlib inline\n",
    "plt.imshow(some_digit_img,cmap=matplotlib.cm.binary)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.neighbors import KNeighborsClassifier"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "y_train=y_train.astype('int32')\n",
    "y_test=y_test.astype('int32')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 选出为1的训练标签\n",
    "y_train_1=(y_train==1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 距离计算 kn模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='minkowski',\n",
       "           metric_params=None, n_jobs=1, n_neighbors=5, p=2,\n",
       "           weights='uniform')"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "kn_clf=KNeighborsClassifier()\n",
    "kn_clf.fit(X_train,y_train_1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "some_digit=[some_digit]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ True])"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "kn_clf.predict(some_digit)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.model_selection import cross_val_score\n",
    "from sklearn.metrics import precision_score\n",
    "from sklearn.metrics import recall_score\n",
    "from sklearn.model_selection import cross_val_predict"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#交叉验证\n",
    "y_train_pred=cross_val_score(kn_clf,X_train,y_train_1,cv=2)\n",
    "y_train_pred[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "y_train_pred=cross_val_predict(kn_clf,X_train,y_train_1,cv=2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 计算精度"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "precision=precision_score(y_train_1,y_train_pred) #训练标签和预测的值进行计算\n",
    "print(\"precision:{:.2f}%\".format(precision*100))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 计算召回率"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "recall=recall_score(y_train_1,y_train_pred)\n",
    "print('recall:{:.2f}%'.format(recall*100))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 网格搜索，确定最优的参数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.model_selection import GridSearchCV"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "para_grid=[\n",
    "    {\"weight\":['uniform'],'n_neightbors':[i for i in range(1,11)]}\n",
    "    {\"weight\":[\"distance\"],'n_neightbors':[i for i in range(1,11)]}\n",
    "]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "final_kn_clf=GridSearchCV(kn_clf,param_grid,cv=3,\n",
    "                         scoring='accuracy')\n",
    "final_kn_clf.fit(X_train,y_train_1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "final_kn_clf.predict(some_digit)#验证"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "final_kn_clf.best_estimator_#最佳参数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#根据最优值来制造最佳的分类器\n",
    "kn_clf_new=KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='minkowski',\n",
    "                     metric_params=None, n_jobs=None, n_neighbors=1, p=2,\n",
    "                     weights='uniform')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 交叉验证\n",
    "y_train_pred=cross_val_predict(kn_clf_new,X_train,y_train_1,cv=2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#计算精度\n",
    "precision=precision_score(y_train_1,y_train_pred)\n",
    "print('precision:{:.2f}%'.format(precision*100))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#计算召回率\n",
    "recall=recall_score(y_train_1,y_train_pred)\n",
    "print('recall:{:.2f}%'.format(recall*100))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "y_test=y_test.astype('int32')\n",
    "y_test_1=(y_test==1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 验证测试集合"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "y_test_pred=cross_val_predict(kn_clf_new,X_test,y_test_1,cv=2)\n",
    "precision=precision_score(y_test_1,y_test_pred)\n",
    "recall=recall_score(y_test_1,y_test_pred)\n",
    "print('precision:{:.2f}%'.format(precision*100))\n",
    "print('recall:{:.2f}%'.format(recall*100))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
